home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / p063b9s.zip / UNIT / NODELIST.PAS < prev    next >
Pascal/Delphi Source File  |  1997-03-02  |  43KB  |  1,216 lines

  1. UNIT NodeList;
  2. {╔══════════════════════════════════════════════════════════════════════════╗}
  3. {║ Read/Write nodelist for QBBS/V6/RA/SBBS/V7    Last changed: 02.03.97  SA ║}
  4. {║                                                                          ║}
  5. {║                         (C) Copyright 1989-97 by                         ║}
  6. {║       Dan Wulff, Jens Sandalgaard, Steen Christensen & S¢ren Ager        ║}
  7. {║                                                                          ║}
  8. {║ This source may not be given to anybody, without the written permission  ║}
  9. {║ from The Portal Team.                                                    ║}
  10. {╚══════════════════════════════════════════════════════════════════════════╝}
  11. {$I POPDEFS.INC}
  12.  
  13. INTERFACE
  14.  
  15. USES Use32, Dos, OpLArray, PoPTypes;
  16.  
  17. CONST
  18.   nlf_CrashMail =   16;
  19.   nlf_HubNode   = 4096;
  20.  
  21.   NodeListPathStr : String[67]='';
  22.  
  23. TYPE
  24.   { Nodelist Records ******************************************* }
  25.  
  26.   QBBSNodeTypes      = (ntZone, ntRegion, ntNet, ntNode);
  27.  
  28.   QBBSNodeIdxRecord  = record
  29.     NodeType       : QBBSNodeTypes;
  30.     Number,
  31.     Cost           : SmallWord;
  32.     RawFile        : Byte;
  33.     RawPos         : LongInt;
  34.   end;
  35.  
  36.   NewNodeList   =RECORD
  37.                      NetNumber,
  38.                      NodeNumber     : SmallInt;
  39.                      Cost           : SmallWord;
  40.                      SystemName     : ARRAY[1..34] OF Char;
  41.                      PhoneNumber    : ARRAY[1..40] OF Char;
  42.                      MiscInfo       : ARRAY[1..30] OF Char;
  43.                      Password       : ARRAY[1..8] OF Char;
  44.                      RealCost       : SmallWord;
  45.                      HubNode        : SmallInt; { or Point if Bit 12 set in NodeFlags }
  46.                      BaudRate       : Byte;
  47.                      ModemType      : Byte;
  48.                      NodeFlags      : SmallWord;
  49.                      NodeFiller     : SmallWord;
  50.                    END;
  51.  
  52.   NewNodeListIndex=RECORD
  53.                      Node           : SmallInt;
  54.                      Net            : SmallInt;
  55.                    END;
  56.  
  57.   NodeExtra=RECORD
  58.     Name : s12;
  59.     Time : LongInt;
  60.   END;
  61.  
  62.   VirtualIndexType=RECORD
  63.     Zone,
  64.     Net,
  65.     Node : SmallInt;
  66.   END;
  67.  
  68.   NodeListRecType=RECORD
  69.                       NodeType       : Byte;    { QuickBBS }
  70.                       Adr            : TFidoAddress;
  71.                       Cost           : SmallWord;
  72.                       SystemName     : String[34];
  73.                       PhoneNumber    : String[40];
  74.                       MiscInfo       : String[30];
  75.                       SysopName      : String[30];
  76.                       Password       : String[8];
  77.                       RealCost       : SmallWord;
  78.                       HubNode        : SmallInt; { or Point if Bit 12 in Flags set }
  79.                       BaudRate       : SmallWord; (* Byte *)
  80.                       ModemType      : Byte;
  81.                       Flags          : SmallWord;
  82.                     END;
  83. CONST
  84.   TranslationTable      : Pointer = NIL;
  85.   CurrentCostTable      : Pointer = NIL;
  86.  
  87. VAR
  88.   NodeListIndex         : OpArray;
  89.   NodeListIndexNum      : Word;
  90.   NodeListEntry         : NodeListRecType;
  91.   NodePos               : LongInt;
  92.  
  93.   CurrentTextFileNumber : Byte;
  94.   CurrentTranslatCount  : WORD;
  95.  
  96.   CurrentGeneralCost,
  97.   CurrentCostCount      : WORD;
  98.  
  99.   {-------------------------------------------------------------------------}
  100.   { Call with Zone, Net, Node of the Board you want to find in the          }
  101.   { nodelist, returns True if the board is found.                           }
  102.   { The NlPath MUST end with a '\', and contain no filename (only the       }
  103.   { path).                                                                  }
  104.   { The board info is returned in NListRec (see definition above).          }
  105.   {-------------------------------------------------------------------------}
  106.  
  107. PROCEDURE DisplaySingleNode(CONST Address: TFidoAddress);
  108. PROCEDURE InitialiseNodelist(CONST NlPath: PathStr; NLType: NodeListType);
  109. PROCEDURE DeAllocateNodeListIndex;
  110. FUNCTION  FindFirstNode(VAR NListRec: NodeListRecType) : Boolean;
  111. FUNCTION  FindNextNode(VAR NListRec: NodeListRecType) : Boolean;
  112. FUNCTION  FindPreviousNode(VAR NListRec: NodeListRecType) : Boolean;
  113. FUNCTION  FindNode(CONST Address: TFidoAddress; VAR NlistRecZ: NodeListRecType): Boolean;
  114. FUNCTION  WriteNode(CONST NListRec: NodeListRecType): Boolean;
  115. PROCEDURE ReadTranslationTable(Silent: Boolean);
  116. FUNCTION  PhoneTranslation(ph: S60): S60;
  117. PROCEDURE GetSpecialModemInfo(CONST s: STRING; VAR mt: Byte; VAR br: SmallWord);
  118. FUNCTION  ListExtension(CONST FName: S12): S12;
  119. FUNCTION  ReadCostTable(Silent: Boolean): Boolean;
  120. FUNCTION  FindCost(CONST Phone: S60): WORD;
  121. FUNCTION  GetSysOpName(CONST Adr: TFidoAddress): S40;
  122.  
  123. IMPLEMENTATION
  124.  
  125. USES OpCrt, OpWindow, OpString, OpRoot,
  126.      LogFile, MailUtil, StrUtil, OproUtil, FileUtil, InterCom, BTree,
  127.      Opus_173, MTask, NetFile, Globals, Util, Display;
  128.  
  129.   FUNCTION ReadCostTable(Silent: Boolean): Boolean;
  130.   VAR
  131.     s : STRING;
  132.     CurrentCost:WORD;
  133.     f : TBufTextFile;
  134.     KeyWord : S20;
  135.     Test : Integer;
  136.     p : Pointer;
  137.   BEGIN
  138.     ReadCostTable:=False;
  139.     CurrentGeneralCost:=0;
  140.     CurrentCostCount:=0;
  141.     IF Cfg.NLCompiler.costfilename<>'' THEN
  142.     BEGIN
  143.       IF NOT Silent THEN
  144.         Write('Reading COST Table from "'+JustFileName(cfg.NLCompiler.CostFileName+'". '));
  145.       IF f.Init(Cfg.NlCompiler.CostFileName, SOpenRead+ShareDenyW, 2048) THEN
  146.       BEGIN
  147.         GetMem(p,SizeOf(CostTab));
  148.         WHILE NOT f.EoF DO
  149.         BEGIN
  150.           f.ReadLn(s);
  151.           IF Trim(s)<>'' THEN
  152.           BEGIN
  153.             s:=Trim(StUpCase(s)+' ');
  154.             keyword:=nextword(' ',s);
  155.             IF Keyword='GENERAL' THEN
  156.             BEGIN
  157.               keyword:=nextword(' ',s);
  158.               Val(keyword,CurrentGeneralCost,test);
  159.               IF test<>0 THEN
  160.               BEGIN
  161.                 f.Done;
  162.                 EXIT;
  163.               END;
  164.             END ELSE
  165.               IF Keyword='COST' THEN
  166.               BEGIN
  167.                 Keyword:=NextWord(' ',s);
  168.                 Val(keyword,currentcost,test);
  169.                 IF Test<>0 THEN
  170.                 BEGIN
  171.                   f.Done;
  172.                   EXIT;
  173.                 END;
  174.               END ELSE
  175.               BEGIN
  176.                 Inc(CurrentCostCount);
  177.                 WITH costtab(p^)[CurrentCostCount] DO
  178.                 BEGIN
  179.                   prefix:=KeyWord;
  180.                   cost:=currentcost;
  181.                 END;
  182.               END;
  183.           END;
  184.         END;
  185.         f.Done;
  186.         GetMem(CurrentCostTable,SizeOf(CostType)*CurrentCostCount);
  187.         Move(p^,CurrentCostTable^,SizeOf(CostType)*CurrentCostCount);
  188.         FreeMem(p,SizeOf(CostTab));
  189.         IF NOT Silent THEN WriteLn(CurrentCostCount,' read');
  190.         ReadCostTable:=True;
  191.       END ELSE
  192.         IF NOT Silent THEN
  193.           WriteLn('The file containing the Cost Table is missing....');
  194.     END;
  195.   END;
  196.  
  197.   PROCEDURE ClearCurrentCostTable;
  198.   BEGIN
  199.     IF CurrentCostTable<>NIL THEN
  200.     BEGIN
  201.       FreeMemCheck(CurrentCostTable,SizeOf(CostType)*CurrentCostCount);
  202.       CurrentCostCount:=0;
  203.     END;
  204.   END;
  205.  
  206.   FUNCTION FindCost(CONST Phone: S60): Word;
  207.   VAR
  208.     Prefix : S10;
  209.     i      : Integer;
  210.     p      : Pointer;
  211.     Cost   : Word;
  212.     Found  : Boolean;
  213.   BEGIN
  214.     IF CurrentCostCount<>0 THEN
  215.     BEGIN
  216.       p:=CurrentCostTable;
  217.       Cost:=0; i:=0; Found:=False;
  218.       REPEAT
  219.         Inc(i);
  220.         Prefix:=Filter(CostTab(p^)[i].Prefix, ['-']);
  221.         IF Prefix=Copy(Filter(Phone, ['-']), 1, Length(Prefix)) THEN
  222.         BEGIN
  223.           Cost:=CostTab(p^)[i].Cost;
  224.           Found:=True;
  225.         END;
  226.       UNTIL (i=CurrentCostCount) OR Found;
  227.       IF NOT Found THEN FindCost:=CurrentGeneralCost ELSE FindCost:=Cost;
  228.     END ELSE
  229.       FindCost:=0;
  230.   END;
  231.  
  232.   PROCEDURE GetSpecialModemInfo(CONST s: STRING; VAR mt: Byte; VAR br: SmallWord);
  233.   VAR
  234.     i : Byte;
  235.   BEGIN
  236.     mt:=0;
  237.     FOR i:=0 TO 7 DO
  238.       IF (Cfg.NLCompiler.MTypeStr[i]<>'') AND (Pos(Cfg.NLCompiler.MTypeStr[i], s)>0) THEN
  239.         mt:=mt+(1 SHL i);
  240.  
  241.     FOR i:=0 TO 7 DO
  242.       IF (1 SHL Cfg.Modem.ModemType[i].Bit) AND mt<>0 THEN
  243.       BEGIN
  244.         br:=Cfg.Modem.ModemType[i].Baud;
  245.         Break;
  246.       END;
  247.   END;
  248.  
  249.   PROCEDURE DisposeTranslationTable;
  250.   BEGIN
  251.     IF TransLationTable<>NIL THEN
  252.     BEGIN
  253.       FreeMemcHECK(TranslationTable,SizeOf(TNLTranslat)*CurrentTranslatCount);
  254.       CurrentTranslatCount:=0;
  255.     END;
  256.   END;
  257.  
  258.   FUNCTION PhoneTranslation(ph: S60): S60;
  259.   VAR
  260.     i : Integer;
  261.     HaveRead,
  262.     InternationalNumber : Boolean;
  263.   BEGIN
  264.     InternationalNumber:=(Copy(ph,1,Length(Cfg.NLCompiler.OurPrefix))<>Cfg.NLCompiler.ourprefix);
  265.     HaveRead:=CurrentTranslatCount=0;
  266.     IF HaveRead THEN ReadTranslationTable(True);
  267.     FOR i:=1 TO CurrentTranslatCount DO
  268.     BEGIN
  269.       IF (Copy(ph,1,Length(NLTranslatTab(TranslationTable^)[i].NumFrom))=NLTranslatTab(TranslationTable^)[i].NumFrom) THEN
  270.       BEGIN
  271.         Delete(ph,1,Length(NLTranslatTab(TranslationTable^)[i].NumFrom));
  272.         Insert(NLTranslatTab(TranslationTable^)[i].NumTo,ph,1);
  273.         Break;
  274.       END;
  275.     END;
  276.     IF InternationalNumber THEN Insert(Cfg.NLCompiler.IntPrefix,ph,1);
  277.     IF HaveRead THEN DisposeTranslationTable;
  278.     PhoneTranslation:=ph;
  279.   END;
  280.  
  281.   PROCEDURE ReadTranslationTable(Silent: Boolean);
  282.   VAR
  283.     f : TNetFile;
  284.   BEGIN
  285.     IF TranslationTable<>NIL THEN DisposeTransLationTable;
  286.     CurrentTranslatCount:=0;
  287.     IF NOT Silent THEN Write('Reading translation table. ');
  288.     IF NOT f.Open(StartPath+PoPNLTranslateFileName,SizeOf(TNLTranslat),False) THEN EXIT;
  289.     CurrentTranslatCount:=f.FileSize;
  290.     IF CurrentTranslatCount>0 THEN
  291.     BEGIN
  292.       GetMem(TranslationTable,SizeOf(TNLTranslat)*CurrentTranslatCount);
  293.       f.BlockRead(TranslationTable^, CurrentTranslatCount);
  294.     END;
  295.     f.Close;
  296.     IF NOT Silent THEN WriteLn(CurrentTranslatCount,' read.');
  297.   END;
  298.  
  299.   FUNCTION CalcNewZone:Integer;
  300.   VAR
  301.     i:WORD;
  302.     idx:NewNodeListIndex;
  303.   BEGIN
  304.     FOR i:=NodePos DOWNTO 1 DO
  305.     BEGIN
  306.       NodeListIndex.RetA(i, 0, idx);
  307.       IF idx.node=-2 THEN
  308.       BEGIN
  309.         CalcNewZone:=idx.net;
  310.         EXIT;
  311.       END;
  312.     END;
  313.     CalcNewZone:=0;
  314.   END;
  315.  
  316.   PROCEDURE DisplaySingleNode(CONST Address: TFidoAddress);
  317.   VAR
  318.     s,n    : S20;
  319.     Temp   : windowptr;
  320.     i      : Byte;
  321.   BEGIN
  322.     WITH nodelistentry DO
  323.     BEGIN
  324.       n:=Address2Str(Address);
  325.       mywin(Temp, 15, 7, 65, 16, 2, 'NodeList Info for ' + n,True);
  326.       IF NOT FindNode(Address, NodelistEntry) THEN
  327.       BEGIN
  328.         FillChar(NodeListEntry,SizeOf(NodeListEntry),0);
  329.         SystemName:='Unknown System!!!';
  330.       END;
  331.       s:='';
  332.       FOR i:=0 TO 7 DO
  333.         IF (1 SHL Cfg.Modem.ModemType[i].Bit) AND ModemType<>0 THEN
  334.           s:=s+', '+Cfg.NlCompiler.MTypeStr[Cfg.Modem.ModemType[i].Bit];
  335.       WITH Temp^ DO
  336.       BEGIN
  337.         wFastText('Node       : '+n,2,2);
  338.         wFastText('System     : '+SystemName,3,2);
  339.         wFastText('Sysop      : '+SysopName,4,2);
  340.         wFastText('Misc. Info : '+MiscInfo,5,2);
  341.         wFastText('Phone      : '+PhoneNumber,6,2);
  342.         wFastText('Max. baud  : '+Long2Str(BaudRate)+s,7,2);
  343.       END;
  344.       WaitForAction(30);
  345.       KillWindow(Temp);
  346.     END;
  347.   END;
  348.  
  349.   FUNCTION GetSysOpName(CONST Adr: TFidoAddress):S40;
  350.   VAR
  351.     sss,sss2:S60;
  352.     s:S40;
  353.     nl : NodeListRecType;
  354.     tf : TBufTextFile;
  355.   BEGIN
  356.     s:='SysOp';
  357.     IF (Cfg.NodeListTyp<>NewNodeListType) THEN
  358.     BEGIN
  359.       IF FindNode(Adr,Nl) THEN s:=Nl.SysOpName;
  360.     END ELSE
  361.     BEGIN
  362.       IF tf.Init(Cfg.NodeList+'FIDOUSER.LST', SOpenRead+ShareDenyW, Max64k(MaxAvail-2048)) THEN
  363.       BEGIN
  364.         sss2:=Address2Str(Adr);
  365.         WHILE NOT tf.EOF DO
  366.         BEGIN
  367.           tf.ReadLn(sss);
  368.           IF Copy(sss,61-LENGTH(sss2),LENGTH(sss2))=sss2 THEN
  369.           BEGIN
  370.             s:=Trim(Copy(sss,1,40));
  371.             sss2:=Copy(s,1,POS(',',s)-1);
  372.             Delete(s,1,LENGTH(sss2)+1);
  373.             WHILE (s<>'') AND (s[1]=' ') DO
  374.               Delete(s,1,1);
  375.             s:=s+' '+sss2;
  376.             Break;
  377.           END;
  378.         END;
  379.         tf.Done;
  380.       END;
  381.     END;
  382.     GetSysOpName:=s;
  383.   END;
  384.  
  385.   PROCEDURE DeAllocateNodeListIndex;
  386.   BEGIN
  387.     IF (Cfg.NodelistTyp<>Version7) And (NodeListPathStr<>'') THEN
  388.     BEGIN
  389.       NodeListIndex.Done;
  390.       NodeListPathStr:='';
  391.       DisposeTranslationTable;
  392.       ClearCurrentCostTable;
  393.     END;
  394.   END;
  395.  
  396.   FUNCTION ListExtension(CONST FName: S12): S12;
  397.   BEGIN
  398.     CASE Cfg.NodelistTyp OF
  399.       SBBSNodeListType : ListExtension:=FName+'SBS';
  400.       QBBSNodeListType : ListExtension:=FName+'DAT';
  401.       RANodeListType   : ListExtension:=FName+'RA';
  402.     END;
  403.   END;
  404.  
  405.   {--------------------------------------------------------------------------}
  406.   { Call this to initialise the nodelist-unit                                }
  407.   {--------------------------------------------------------------------------}
  408.  
  409.   PROCEDURE InitialiseNodelist(CONST NlPath: PathStr; NLType: NodeListType);
  410.   VAR
  411.     i, j           : Word;
  412.     NodeListFile   : TNetFile;
  413.     QBBSNodeListIdx: ARRAY[1..500] OF QBBSNodeIdxRecord;
  414.     NewNodeListIdx : ARRAY[1..1250] OF NewNodeListIndex ABSOLUTE QBBSNodeListIdx;
  415.     Error          : Boolean;
  416.     NodeBufferSize : LongInt;
  417.     FName          : S12;
  418.   BEGIN
  419.     Error:=False;
  420.     IF Cfg.NodelistTyp=Version7 THEN
  421.     BEGIN
  422.       NodePos:=200000;
  423.       Exit;
  424.     END;
  425.     IF NodeListPathStr=#255 THEN
  426.     BEGIN
  427.       IF MaxAvail>10240 THEN NodeBufferSize:=MaxAvail-10240 ELSE
  428.       BEGIN
  429.         NodeBufferSize:=0;
  430.         Error:=True;
  431.       END;
  432.     END ELSE
  433.       NodeBufferSize:=MaxAvail-65536;
  434.     IF NOT Error THEN
  435.     BEGIN
  436.       NodeListPathStr:=AddBackSlash(NlPath);
  437.       NodeListIndexNum:=0;
  438.       OpenLockFile;
  439.       REPEAT
  440.         GiveUpTime;
  441.       UNTIL NetGrabFile(NetNLFile) or KeyPressed;
  442.       CASE NLType OF
  443.         NewNodelistType : BEGIN
  444.                             IF NodeListFile.Open(NodeListPathStr+'NODELIST.IDX',SizeOf(NewNodeListIndex), False) THEN
  445.                             BEGIN
  446.                               IF NodeListFile.FileSize<65500 THEN
  447.                               BEGIN
  448. {                               NodeListIndex.Init(MakeTaskFileName('PORTAL.NIB'), FileSize(NodeListFile)+100, 4, 65536);}
  449.                                 NodeListIndex.Init(NodeListFile.FileSize+100, 1, 4, MakeTaskFileName(PoPNodelistIdxBuffer),
  450.                                                    NodeBufferSize, lDeleteFile, DefaultPriority);
  451.                                 WHILE NOT NodeListFile.EoF DO
  452.                                 BEGIN
  453.                                   NodeListFile.BlockReadNum(NewNodeListIdx, 1250, j);
  454.                                   FOR i:=1 TO j DO
  455.                                   BEGIN
  456.                                     NodeListIndex.SetA(NodeListIndexNum, 0, NewNodeListIdx[i]);
  457.                                     Inc(NodeListIndexNum);
  458.                                   END;
  459.                                 END;
  460.                               END ELSE
  461.                               BEGIN
  462.                                 AddLog('!', 'Nodelist file: '+NodeListPathStr+'NODELIST.IDX is too big!');
  463.                                 Error:=True;
  464.                               END;
  465.                               NodeListFile.Close;
  466.                             END ELSE
  467.                               Error:=True;
  468.                           END;
  469.         QBBSNodelistType,
  470.         SBBSNodeListType,
  471.         RANodeListType  : BEGIN
  472.                             FName:=ListExtension('NODEIDX.');
  473.                             IF NodeListFile.Open(NodeListPathStr+FName,SizeOf(QBBSNodeIdxRecord), False) THEN
  474.                             BEGIN
  475.                               IF NodeListFile.FileSize<65500 THEN
  476.                               BEGIN
  477.                                 NodeListIndex.Init(NodeListFile.FileSize, 1, 10, MakeTaskFileName(PoPNodelistIdxBuffer),
  478.                                                    NodeBufferSize, lDeleteFile, DefaultPriority);
  479.  
  480.                                 WHILE NOT NodeListFile.EoF DO
  481.                                 BEGIN
  482.                                   NodeListFile.BlockReadNum(QBBSNodeListIdx, 500, j);
  483.                                   FOR i:=1 TO j DO
  484.                                   BEGIN
  485.                                     NodeListIndex.SetA(NodeListIndexNum, 0, QBBSNodeListIdx[i]);
  486.                                     Inc(NodeListIndexNum);
  487.                                   END;
  488.                                 END;
  489.                               END ELSE
  490.                               BEGIN
  491.                                 AddLog('!', 'Nodelist file: '+NodeListPathStr+FName+' is too big!');
  492.                                 Error:=True;
  493.                               END;
  494.                               NodeListFile.Close;
  495.                             END ELSE
  496.                               Error:=True;
  497.                           END;
  498.       END;
  499.       NetReleaseFile(NetNLFile);
  500.       CloseLockFile;
  501.     END;
  502.     IF Error THEN NodeListPathStr:='' ELSE
  503.     BEGIN
  504.       IF NLType IN [QBBSNodeListType,SBBSNodeListType,RANodeListType] THEN
  505.       BEGIN
  506.         ReadTranslationTable(True);
  507.         ReadCostTable(True);
  508.       END;
  509.     END;
  510.   END;
  511.  
  512.   {--------------------------------------------------------------------------}
  513.   { Remote access Nodelist                                                   }
  514.   {--------------------------------------------------------------------------}
  515.  
  516.   PROCEDURE ConvRANodeListRec(s: STRING; VAR NodeListRec : NodeListRecType; Zone,Net,Node:Integer);
  517.   VAR
  518.     KeyWord:S12;
  519.     number,Point,test : Integer;
  520.   BEGIN
  521.     KeyWord:=StUpCase(NextWord(',',s));
  522.     Val(NextWord(',',s),Number,test);
  523.     Point:=0;
  524.     IF (KeyWord='ZONE') THEN
  525.     BEGIN
  526.       Zone:=Number;
  527.       Net:=Number;
  528.       Node:=0;
  529.     END ELSE
  530.       IF (KeyWord='HOST') OR (KeyWord='REGION') THEN
  531.       BEGIN
  532.         Net:=Number;
  533.         Node:=0;
  534.       END ELSE
  535.         IF KeyWord='POINT' THEN
  536.         BEGIN
  537.           Point:=Number;
  538.         END ELSE
  539.           Node:=Number;
  540.     FillChar(NodeListRec,SizeOf(NodeListRec),0);
  541.     NodeListRec.Adr.Zone:=Zone;
  542.     NodeListRec.Adr.Net:=Net;
  543.     NodeListRec.Adr.Node:=Node;
  544.     NodeListRec.Adr.Point:=Point;
  545.     NodeListRec.SystemName:=NextWord(',',s);
  546.     Replace(NodeListRec.SystemName,'_',' ',0);
  547.     NodeListRec.MiscInfo:=NextWord(',',s);
  548.     Replace(NodeListRec.MiscInfo,'_',' ',0);
  549.     NodeListRec.SysopName:=NextWord(',',s);
  550.     Replace(NodeListRec.SysOpName,'_',' ',0);
  551.     NodeListRec.PhoneNumber:=NextWord(',',s);
  552.     NodeListRec.Cost:=FindCost(NodeListRec.PhoneNumber);
  553.     NodeListRec.RealCost:=NodeListRec.Cost;
  554.     IF NOT IsOurAddress(NodelistRec.Adr) THEN
  555.       NodeListRec.PhoneNumber:=PhoneTranslation(NodeListRec.PhoneNumber);
  556.     Val(NextWord(',',s),NodeListRec.BaudRate,Test);
  557.     GetSpecialModemInfo(StUpCase(s),NodeListRec.ModemType,NodeListRec.BaudRate);
  558.     s:=s+',';
  559.     WHILE s<>'' DO
  560.     BEGIN
  561.       KeyWord:=NextWord(',',s);
  562.       IF KeyWord='CM' THEN NodeListRec.Flags:=NodeListRec.Flags OR nlf_CrashMail;
  563.     END;
  564.   END;
  565.  
  566.   {--------------------------------------------------------------------------}
  567.   { Version 6 Nodelist                                                       }
  568.   {--------------------------------------------------------------------------}
  569.  
  570.   PROCEDURE ConvNewNodelistRec(NodelistRecZ: NewNodeList; VAR NodelistRec: NodeListRecType; RealZone : Integer);
  571.   BEGIN
  572.     WITH NodelistRec DO
  573.     BEGIN
  574.       Adr.Zone:=RealZone;
  575.       Adr.Net:=NodelistRecZ.NetNumber;
  576.       Adr.Node:=NodelistRecZ.NodeNumber;
  577.       Cost:=NodelistRecZ.Cost;
  578.       SystemName:=Asciiz2Str(NodelistRecZ.SystemName, 34);
  579.       PhoneNumber:=Asciiz2Str(NodelistRecZ.PhoneNumber, 40);
  580.       MiscInfo:=Asciiz2Str(NodelistRecZ.MiscInfo, 30);
  581.       Password:=Asciiz2Str(NodelistRecZ.Password, 8);
  582.       RealCost:=NodelistRecZ.RealCost;
  583.       BaudRate:=NodelistRecZ.BaudRate * 300;
  584.       ModemType:=NodelistRecZ.ModemType;
  585.       Flags:=NodelistRecZ.NodeFlags;
  586.       HubNode:=NodelistRecZ.HubNode;
  587.       IF (Flags AND nlf_HubNode)<>0 THEN
  588.       BEGIN
  589.         Adr.Point:=HubNode;
  590.         HubNode:=0;
  591.       END;
  592.     END;
  593.   END;
  594.  
  595.   PROCEDURE ReConvNewNodelistRec(VAR NodelistRecZ: NewNodeList; CONST NodelistRec: NodeListRecType);
  596.   BEGIN
  597.     WITH NodelistRec DO
  598.     BEGIN
  599.       NodelistRecZ.NetNumber:=Adr.Net;
  600.       NodelistRecZ.NodeNumber:=Adr.Node;
  601.       NodelistRecZ.Cost:=Cost;
  602.       Str2AsciiZ(SystemName, NodelistRecZ.SystemName,34);
  603.       Str2AsciiZ(PhoneNumber, NodelistRecZ.PhoneNumber,40);
  604.       Str2AsciiZ(MiscInfo, NodelistRecZ.MiscInfo,30);
  605.       Str2AsciiZ(Password, NodelistRecZ.Password,8);
  606.       NodelistRecZ.RealCost:=RealCost;
  607.       IF Adr.Point=0 THEN
  608.         NodelistRecZ.HubNode:=HubNode
  609.       ELSE
  610.       BEGIN
  611.         NodelistRecZ.HubNode:=Adr.Point;
  612.         NodelistRecZ.NodeFlags:=NodelistRecZ.NodeFlags OR nlf_HubNode;   {???}
  613.       END;
  614.       NodelistRecZ.BaudRate:=BaudRate DIV 300;
  615.       NodelistRecZ.ModemType:=ModemType;
  616.       NodelistRecZ.NodeFlags:=Flags;
  617.     END;
  618.   END;
  619.  
  620.   FUNCTION GetNewNodelistInfo(RecNo: LongInt; VAR NListRec: NewNodeList): Boolean;
  621.   VAR
  622.     NodeList : TNetFile;
  623.   BEGIN
  624.     GetNewNodelistInfo:=False;
  625.     IF Nodelist.Open(NodeListPathStr+'NODELIST.DAT', SizeOf(NewNodelist), False) THEN
  626.     BEGIN
  627.       Nodelist.GetRec(NListRec,RecNo,NoKeep,Wait);
  628.       GetNewNodelistInfo:=(Nodelist.IoResult=0);
  629.       NodeList.Close;
  630.     END;
  631.   END;
  632.  
  633.   FUNCTION SaveNewNodelistInfo(RecNo : LongInt; VAR NListRec : NewNodeList) : Boolean;
  634.   VAR
  635.     NodeList, NodeListIdx : TNetFile;
  636.     NListIdxRec : NewNodeListIndex;
  637.   BEGIN
  638.     SaveNewNodelistInfo:=True;
  639.     Nodelist.Open(NodeListPathStr+'NODELIST.DAT',SizeOf(NewNodeList),False);
  640.     Nodelist.PutRec(NListRec, RecNo);
  641.     IF Nodelist.IoResult=0 THEN
  642.     BEGIN
  643.       Nodelist.Close;
  644.       WITH NListRec DO
  645.       BEGIN
  646.         IF (NodeFlags AND nlf_HubNode)=0 THEN
  647.         BEGIN
  648.           NListIdxRec.Net:=NetNumber;
  649.           NListIdxRec.Node:=NodeNumber;
  650.         END ELSE
  651.         BEGIN
  652.           NListIdxRec.Net:=-1;
  653.           NListIdxRec.Node:=HubNode;
  654.         END;
  655.       END;
  656.       NodeListIdx.Open(NodeListPathStr+'NODELIST.IDX',SizeOf(NewNodeListIndex),False);
  657.       NodeListIdx.PutRec(NListIdxRec, RecNo);
  658.       NodeListIdx.Close;
  659.     END ELSE
  660.       SaveNewNodelistInfo:=False;
  661.   END;
  662.  
  663.   FUNCTION GetV7Info(RecNo: LongInt; VAR NlRec: NodelistRecType): Boolean;
  664.   VAR
  665.     s : String;
  666.     V7 : Version7NlType;
  667.     f : TNetFile;
  668.   BEGIN
  669.     FillChar(NlRec,SizeOf(NlRec),0);
  670.     GetV7Info:=True;
  671.     f.Open(Cfg.Nodelist+'NODEX.DAT',1,False);
  672.     f.Seek(RecNo);
  673.     f.BlockRead(V7,SizeOf(Version7NlType));
  674.     f.BlockRead(NlRec.PhoneNumber[1],V7.Phone_Len); NlRec.PhoneNumber[0]:=Char(V7.Phone_Len);
  675.     f.BlockRead(NlRec.Password[1],V7.Password_Len); NlRec.Password[0]:=Char(V7.Password_Len);
  676.     f.BlockRead(s[1],V7.Pack_Len); s[0]:=Char(V7.Pack_Len);
  677.     f.Close;
  678.     s:=unpack(s);
  679.     WITH NlRec DO
  680.     BEGIN
  681.       Adr.Zone:=V7.Zone;
  682.       Adr.Net:=V7.Net;
  683.       Adr.Node:=V7.Node;
  684.       Cost:=V7.CallCost;
  685.       SystemName:=FancyStr(Copy(s,1,V7.BName_Len));
  686.       MiscInfo:=FancyStr(Copy(s,V7.BName_Len+V7.SName_Len+1,V7.CName_Len));
  687.       SysopName:=FancyStr(Copy(s,V7.BName_Len+1,V7.SName_Len));
  688.       RealCost:=V7.CallCost;
  689.       HubNode:=V7.HubNode;
  690.       BaudRate:=V7.BaudRate*300;
  691.       ModemType:=V7.ModemType;
  692.       Flags:=V7.NodeFlags;
  693.       IF (Flags AND nlf_HubNode)<>0 THEN
  694.       BEGIN
  695.         Adr.Point:=HubNode;
  696.         HubNode:=0;
  697.       END;
  698.     END;
  699.   END;
  700.  
  701.   FUNCTION FindNode(CONST Address: TFidoAddress; VAR NlistRecZ : NodeListRecType) : Boolean;
  702.   VAR
  703.     ew,KeyWord: S6;
  704.     s         : STRING;
  705.     buf       : ARRAY[1..10] OF CHAR;
  706.     Found     : Boolean;
  707.     i         : LongInt;
  708.     NewIdx    : NewNodelistIndex ABSOLUTE buf;
  709.     QI        : QBBSNodeIdxRecord ABSOLUTE buf;
  710.     NListRec  : NewNodeList;
  711.     Rf        : FILE OF NodeExtra;
  712.     rx        : NodeExtra;
  713.     tf        : TBufTextFile;
  714.     add       : Byte;
  715.     b,
  716.     CurZone   : Integer;
  717.     FName     : S12;
  718.  
  719.     PROCEDURE FindRawNode(NP:WORD);
  720.     VAR
  721.       NextOffSet : LongInt;
  722.       ss : STRING;
  723.       IORes : Integer;
  724.     BEGIN
  725.       Found:=False;
  726.       FName:=ListExtension('NODEINC.');
  727.       Assign(rf,NodeListPathStr+FName);
  728.       FileMode:=ShareRead+ShareDenyNone;
  729.       RESET(rf);
  730.       IF IOResult=0 THEN
  731.       BEGIN
  732.         Seek(rf,QI.RawFile-1);
  733.         IORes:=IOResult;
  734.         IF IORes=0 THEN READ(rf,rx);
  735.         IORes:=IOResult;
  736.         CurrentTextFileNumber:=QI.RawFile;
  737.         Close(rf);
  738.         IF (IoRes=0) AND tf.Init(NodeListPathStr+rx.name, SOpenRead+ShareDenyNone, Max64k(10240)) THEN
  739.         BEGIN
  740.           tf.Seek(QI.RawPos);
  741.           IF IOResult=0 THEN
  742.           BEGIN
  743.             tf.ReadLn(s);
  744.             ss:=StUpCase(Copy(s,1,4));
  745.             IF (Address.Node=0) AND
  746.                (((ss='ZONE') AND (Address.Net=Address.Net)) OR
  747.                 (((ss='HOST') OR (ss='REGI')) AND (Address.Node=0))) THEN
  748.             BEGIN
  749.               Found:=True;
  750.               NodePos:=tf.GetPos-Length(s)-2;
  751.             END ELSE
  752.             BEGIN
  753.               IF NP<NodeListIndexNum-2 THEN
  754.               BEGIN
  755.                 NodeListIndex.RetA(NP+1, 0, buf);
  756.                 CASE Cfg.NodeListTyp OF
  757.                   RaNodeListType,
  758.                   SBBSNodeListType,
  759.                   QBBSNodeListType : BEGIN
  760.                                        IF QI.RawFile=CurrentTextFileNumber THEN
  761.                                          NextOffSet:=QI.RawPos
  762.                                        ELSE
  763.                                          NextOffSet:=$7FFFFFFF;
  764.                                      END;
  765.                 END;
  766.               END ELSE
  767.                 NextOffSet:=tf.GetSize+1;
  768.               IF NextOffSet=0 THEN NextOffSet:=tf.GetSize+1;
  769.               Found:=False;
  770.               KeyWord:='HOST';
  771.               ew:='';
  772.               WHILE NOT tf.EOF AND NOT Found AND (NextOffset>tf.GetPos) DO
  773.               BEGIN
  774.                 tf.ReadLn(s);
  775.                 IF Copy(s,1,1)<>';' THEN
  776.                 BEGIN
  777.                   IF (s<>'') AND (s[1]<>',') THEN add:=1 ELSE add:=0;
  778.                   KeyWord:=StUpCase(ExtractWord(add,s,[',']));
  779.                   ew:=ExtractWord(1+add,s,[',']);
  780.                   IF (KeyWord<>'POINT') AND
  781.                     ((ew=Long2Str(Address.Node)) OR ((ss='ZONE') AND (ew=Long2Str(Address.Net)))) THEN
  782.                   BEGIN
  783.                     IF (Address.Point=0) AND (KeyWord<>'POINT') THEN
  784.                     BEGIN
  785.                       Found:=True;
  786.                       NodePos:=tf.GetPos-Length(s)-2;
  787.                     END ELSE
  788.                     BEGIN
  789.                       IF (Address.Node=0) AND (ew<>'0') AND (ss<>'ZONE') THEN
  790.                       BEGIN
  791.                         Break;
  792.                       END;
  793.                       ew:='';
  794.                       KeyWord:='POINT';
  795.                       WHILE NOT tf.EOF AND NOT Found AND (NextOffset>tf.GetPos) AND
  796.                            (KeyWord='POINT') AND (ew<>Long2Str(Address.Point)) DO
  797.                       BEGIN
  798.                         tf.ReadLn(s);
  799.                         IF Copy(s,1,1)<>';' THEN
  800.                         BEGIN
  801.                           IF (s<>'') AND (s[1]<>',') THEN add:=1 ELSE add:=0;
  802.                           KeyWord:=StUpCase(ExtractWord(add,s,[',']));
  803.                           ew:=ExtractWord(1+add,s,[',']);
  804.                           IF (KeyWord='POINT') AND (ew=Long2Str(Address.Point)) THEN
  805.                           BEGIN
  806.                             Found:=True;
  807.                             NodePos:=tf.GetPos-Length(s)-2;
  808.                           END;
  809.                         END;
  810.                       END;
  811.                       IF NOT Found THEN NextOffSet:=-1;
  812.                     END;
  813.                   END;
  814.                 END;
  815.               END;
  816.             END;
  817.           END;
  818.           tf.Done;
  819.         END;
  820.       END;
  821.     END;
  822.  
  823.   BEGIN
  824.     FindNode:=False;
  825.     FillChar(NlistRecZ, SizeOf(NListRecZ), 0);
  826.     IF Cfg.NodelistTyp=Version7 THEN
  827.     BEGIN
  828.       Found:=FindKey(Cfg.Nodelist+'NODEX.NDX',i,Address2Opus(Address));
  829.     END ELSE
  830.     BEGIN
  831.       IF CheckICToDo(ICTDReReadNLIdx) THEN
  832.       BEGIN
  833.         DeAllocateNodeListIndex;
  834.         InitialiseNodeList(Cfg.NodeList,Cfg.NodeListTyp);
  835.       END;
  836.       Found:=False;
  837.       IF NodeListIndexNum=0 THEN EXIT;
  838.       i:=-1; CurZone:=0;
  839.       REPEAT
  840.         REPEAT
  841.           Inc(i);
  842.           NodeListIndex.RetA(i, 0, buf);
  843.           WITH Address DO
  844.             CASE Cfg.NodeListTyp OF
  845.               NewNodeListType  : BEGIN
  846.                                    IF NewIdx.Node=-2 THEN CurZone:=NewIdx.Net;
  847.                                    IF NewIdx.Node<0 THEN NewIdx.Node:=0;
  848.                                    Found:=((Zone=CurZone) And (Net=NewIdx.Net) And (Node=NewIdx.Node));
  849.                                  END;
  850.               RANodeListType,
  851.               SBBSNodelistType,
  852.               QBBSNodeListType : BEGIN
  853.                                    IF (QI.NodeType=ntZone) THEN
  854.                                    BEGIN
  855.                                      CurZone:=QI.Number;
  856.                                      {QI.Number:=0;}
  857.                                    END;
  858.                                    Found:=(CurZone=Zone) AND ((QI.Number=Net) OR (Net=0));
  859.                                    IF Found THEN FindRawNode(i);
  860.                                  END;
  861.             END;
  862.         UNTIL Found OR (i>=NodeListIndexNum-1);
  863.         IF Found And (Address.Point<>0) THEN
  864.         BEGIN
  865.           CASE Cfg.NodeListTyp OF
  866.             NewNodeListType : BEGIN
  867.                                 Found:=False;
  868.                                 REPEAT
  869.                                   Inc(i);
  870.                                   NodeListIndex.RetA(i, 0, buf);
  871.                                   IF Cfg.NodeListTyp=NewNodeListType THEN
  872.                                     Found:=((NewIdx.Net=-1) And (Address.Point=NewIdx.Node));
  873.                                 UNTIL Found OR (i=NodeListIndexNum-1) OR
  874.                                      (NewIdx.Net<>-1);
  875.                               END;
  876.             RANodeListType,
  877.             QBBSNodeListType,
  878.             SBBSNodeListType: BEGIN
  879.                                 ConvRANodeListRec(s,NListRecZ,Address.Zone,Address.Net,Address.Node);
  880.                               END;
  881.           END;
  882.         END;
  883.       UNTIL Found Or (i>=NodeListIndexNum-1);
  884.     END;
  885.     IF Found THEN
  886.     BEGIN
  887.       FindNode:=True;
  888.       CASE Cfg.NodeListTyp OF
  889.         Version7        : BEGIN
  890.                             IF Not GetV7Info(i,NListRecZ) THEN FindNode:=False;
  891.                           END;
  892.         NewNodelistType : BEGIN
  893.                             NodePos:=i;
  894.                             IF GetNewNodelistInfo(i, NListRec) THEN
  895.                               ConvNewNodelistRec(NListRec, NlistRecZ, Address.Zone)
  896.                             ELSE
  897.                               FindNode:=False;
  898.                           END;
  899.         QBBSNodelistType,
  900.         SBBSNodelistType,
  901.         RANodeListType   : BEGIN
  902.                              ConvRANodeListRec(s,NListRecZ,Address.Zone,Address.Net,Address.Node);
  903.                            END;
  904.       END;
  905.       b:=0;
  906.       FOR i:=0 TO 7 DO
  907.         IF (1 SHL Cfg.Modem.ModemType[i].Bit) AND NListRecZ.ModemType<>0 THEN
  908.         BEGIN
  909.           b:=Cfg.Modem.ModemType[i].Baud;
  910.           Break;
  911.         END;
  912.       IF b<>0 THEN NListRecZ.BaudRate:=b;
  913.     END;
  914.   END;
  915.  
  916.   FUNCTION WriteNode(CONST NListRec : NodeListRecType) : Boolean;
  917.   VAR
  918.     NlistRecZ      : NewNodeList;
  919.     vi             : VirtualIndexType;
  920.   BEGIN
  921.     WriteNode:=True;
  922.     IF Cfg.NodelistTyp=NewNodelistType THEN
  923.     BEGIN
  924.       IF NListRec.Adr.Point=0 THEN
  925.       BEGIN
  926.         vi.zone:=NListRec.Adr.Net;
  927.         vi.net:=NListRec.Adr.Node;
  928.       END
  929.       ELSE
  930.       BEGIN
  931.         vi.Zone:=NListRec.Adr.Point;
  932.         vi.Net:=-1;
  933.       END;
  934.     END ELSE
  935.     BEGIN
  936.       vi.zone:=NListRec.Adr.Zone;
  937.       vi.net:=NListRec.Adr.Net;
  938.       vi.node:=NListRec.Adr.Node;
  939.     END;
  940.     NodeListIndex.SetA(NodePos, 0, vi);
  941.     CASE Cfg.NodeListTyp OF
  942.       NewNodelistType : BEGIN
  943.                           ReConvNewNodelistRec(NlistRecZ, NListRec);
  944.                           IF NOT SaveNewNodelistInfo(NodePos, NlistRecZ) THEN WriteNode:=False;
  945.                         END;
  946.     END;
  947.   END;
  948.  
  949.   FUNCTION FindFirstNode(VAR NListRec : NodeListRecType) : Boolean;
  950.   VAR
  951.     NlistRecZ : NewNodeList;
  952.     Qn        : QBBSNodeIdxRecord;
  953.     TmpAdr    : TFidoAddress;
  954.   BEGIN
  955.     FindFirstNode:=True;
  956.     NodePos:=0;
  957.     FillChar(NListRec, SizeOf(NListRec), 0);
  958.     CASE Cfg.NodeListTyp OF
  959.       NewNodelistType  : BEGIN
  960.                            IF GetNewNodelistInfo(NodePos, NlistRecZ) THEN
  961.                            ConvNewNodelistRec(NlistRecZ, NListRec, CalcNewZone) ELSE FindFirstNode:=False;
  962.                          END;
  963.       QBBSNodelistType,
  964.       SBBSNodelistType,
  965.       RANodeListType   : BEGIN
  966.                            NodeListIndex.RetA(0, 0, Qn);
  967.                            TmpAdr.Zone:=Qn.Number;
  968.                            TmpAdr.Net:=0;
  969.                            TmpAdr.Node:=0;
  970.                            TmpAdr.Point:=0;
  971.                            FindFirstNode:=FindNode(TmpAdr,NListRec);
  972.                          END;
  973.     END;
  974.   END;
  975.  
  976.   FUNCTION FindNextNode(VAR NListRec : NodeListRecType) : Boolean;
  977.   LABEL
  978.     RAAgain;
  979.   VAR
  980.     KeyWord   : S12;
  981.     s         : STRING;
  982.     NlistRecZ : NewNodeList;
  983.     Rf        : TNetFile;
  984.     tf        : TBufTextFile;
  985.     rx        : NodeExtra;
  986.     add       : Byte;
  987.     test      : Integer;
  988.     Number    : Integer;
  989.     Done      : Boolean;
  990.     TmpAdr    : TFidoAddress;
  991.     FName     : S12;
  992.     RecNum    : LONGINT;
  993.   BEGIN
  994.     FindNextNode:=True;
  995.     TmpAdr:=NListRec.Adr;
  996.     FillChar(NListRec, SizeOf(NListRec), 0);
  997.     Inc(NodePos);
  998.     CASE Cfg.NodeListTyp OF
  999.        NewNodelistType : BEGIN
  1000.                            IF GetNewNodelistInfo(NodePos, NlistRecZ) THEN
  1001.                              ConvNewNodelistRec(NlistRecZ, NListRec, CalcNewZone)
  1002.                            ELSE
  1003.                            BEGIN
  1004.                              Dec(NodePos);
  1005.                              FindNextNode:=False;
  1006.                            END;
  1007.                          END;
  1008.       Version7         : BEGIN
  1009.                            IF NextKey(Cfg.Nodelist+'NODEX.NDX',RecNum,Address2Opus(TmpAdr)) THEN
  1010.                              FindNextNode:=GetV7Info(REcNum,NListRec);
  1011.                          END;
  1012.       QBBSNodelistType,
  1013.       SBBSNodelistType,
  1014.       RANodeListType   : BEGIN
  1015.         Dec(NodePos);
  1016. RAAgain:
  1017.         FName:=ListExtension('NODEINC.');
  1018.         IF rf.Open(NodeListPathStr+FName,SizeOf(NodeExtra),False) THEN
  1019.         BEGIN
  1020.           rf.GetRec(rx,CurrentTextFileNumber-1,NoKeep,Wait);
  1021.           rf.Close;
  1022.           IF tf.Init(NodeListPathStr+rx.name, SOpenRead+ShareDenyNone, 10240) THEN
  1023.           BEGIN
  1024.             tf.SetPos(NodePos, PosAbs);
  1025.             IF tf.GetStatus=0 THEN
  1026.             BEGIN
  1027.               tf.ReadLn(s); (* Læs nuv. node *)
  1028.               Done:=False;
  1029.               WHILE NOT tf.EOF AND NOT Done DO
  1030.               BEGIN
  1031.                 tf.ReadLn(s);
  1032.                 IF (s<>'') AND (s[1]<>';') THEN Done:=True;
  1033.               END;
  1034.               tf.Done;
  1035.               IF Not Done THEN
  1036.               BEGIN
  1037.                 Inc(CurrentTextFileNumber);
  1038.                 NodePos:=0;
  1039.                 GOTO RAAgain;
  1040.               END;
  1041.               IF Done THEN
  1042.               BEGIN
  1043.                 IF s[1]<>',' THEN add:=1 ELSE add:=0;
  1044.                 KeyWord:=ExtractWord(1+add,s,[',']);
  1045.                 Val(KeyWord,Number,Test);
  1046.                 KeyWord:=StUpCase(ExtractWord(add,s,[',']));
  1047.                 IF (KeyWord='ZONE') THEN
  1048.                 BEGIN
  1049.                   TmpAdr.Zone:=Number;
  1050.                   TmpAdr.Net :=Number;
  1051.                   TmpAdr.Node:=0;
  1052.                   TmpAdr.Point:=0;
  1053.                 END ELSE
  1054.                   IF (KeyWord='HOST') OR (KeyWord='REGION') THEN
  1055.                   BEGIN
  1056.                     TmpAdr.Net:=Number;
  1057.                     TmpAdr.Node:=0;
  1058.                     TmpAdr.Point:=0;
  1059.                   END ELSE
  1060.                     IF (KeyWord='POINT') THEN
  1061.                     BEGIN
  1062.                       TmpAdr.Point:=Number;
  1063.                     END ELSE
  1064.                       TmpAdr.Node:=Number;
  1065.                 IF FindNode(TmpAdr,NListRec) THEN FindNextNode:=True;
  1066.               END ELSE
  1067.                 FindNextNode:=False;
  1068.             END;
  1069.           END;
  1070.         END ELSE
  1071.           FindNextNode:=False;
  1072.       END;
  1073.     END;
  1074.   END;
  1075.  
  1076.   FUNCTION FindPreviousNode(VAR NListRec : NodeListRecType) : Boolean;
  1077.   LABEL
  1078.     RAAgain;
  1079.   VAR
  1080.     NlistRecZ : NewNodeList;
  1081.     QIdx      : QBBSNodeIdxRecord;
  1082.     Rf, tf    : TNetFile;
  1083.     rx        : NodeExtra;
  1084.     add,ifn   : Byte;
  1085.     OurNet,
  1086.     OurZone,
  1087.     test,i,
  1088.     Number    : Integer;
  1089.     TmpAdr    : TFidoAddress;
  1090.     Done      : Boolean;
  1091.     s         : STRING;
  1092.     FName,
  1093.     KeyWord   : S12;
  1094.     RecNum,io, tfpos : LongInt;
  1095.   BEGIN
  1096.     FindPreviousNode:=True;
  1097.     TmpAdr:=NListRec.Adr;
  1098.     FillChar(NListRec, SizeOf(NListRec), 0);
  1099.     Dec(NodePos);
  1100.     IF NodePos < 0 THEN
  1101.     BEGIN
  1102.       FindPreviousNode:=False;
  1103.       NodePos:=0;
  1104.     END ELSE
  1105.     BEGIN
  1106.       CASE Cfg.NodeListTyp OF
  1107.         NewNodelistType : BEGIN
  1108.                             IF GetNewNodelistInfo(NodePos, NlistRecZ) THEN
  1109.                             ConvNewNodelistRec(NlistRecZ, NListRec, CalcNewZone) ELSE FindPreviousNode:=False;
  1110.                           END;
  1111.         Version7        : BEGIN
  1112.                             IF PrevKey(Cfg.Nodelist+'NODEX.NDX',RecNum,Address2Opus(TmpAdr)) THEN
  1113.                               FindPreviousNode:=GetV7Info(RecNum,NListRec);
  1114.                           END;
  1115.         QBBSNodelistType,
  1116.         SBBSNodelistType,
  1117.         RANodeListType   : BEGIN
  1118.           Inc(NodePos);
  1119. RAAgain:
  1120.           FName:=ListExtension('NODEINC.');
  1121.           IF rf.Open(NodeListPathStr+FName,SizeOf(NodeExtra),False) THEN
  1122.           BEGIN
  1123.             rf.GetRec(rx,CurrentTextFileNumber-1,NoKeep,Wait);
  1124.             rf.Close;
  1125.             IF tf.Open(NodeListPathStr+rx.name,1,False) THEN
  1126.             BEGIN
  1127.               IF NodePos=-2 THEN NodePos:=tf.FileSize;
  1128.               tf.Seek(NodePos);
  1129.               IF tf.IOResult=0 THEN
  1130.               BEGIN
  1131.                 Done:=False;
  1132.                 WHILE (tf.FilePos>0) AND NOT Done DO
  1133.                 BEGIN
  1134.                   tf.ReadLineBack(s);
  1135.                   IF (s<>'') AND (s[1]<>';') THEN Done:=True;
  1136.                 END;
  1137.                 tfpos:=tf.FilePos;
  1138.                 tf.Close;
  1139.                 IF Not Done THEN
  1140.                 BEGIN
  1141.                   NodePos:=-2;
  1142.                   Dec(CurrentTextFileNumber);
  1143.                   GOTO RAAgain;
  1144.                 END;
  1145.                 IF Done THEN
  1146.                 BEGIN
  1147.                   IF s[1]<>',' THEN add:=1 ELSE add:=0;
  1148.                   KeyWord:=ExtractWord(1+add,s,[',']);
  1149.                   Val(KeyWord,Number,Test);
  1150.                   KeyWord:=StUpCase(ExtractWord(add,s,[',']));
  1151.                   IF (KeyWord='ZONE') THEN
  1152.                   BEGIN
  1153.                     TmpAdr.Zone:=Number;
  1154.                     TmpAdr.Net :=Number;
  1155.                     TmpAdr.Node:=0;
  1156.                     TmpAdr.Point:=0;
  1157.                   END ELSE
  1158.                   IF (KeyWord='HOST') OR (KeyWord='REGION') THEN
  1159.                   BEGIN
  1160.                     TmpAdr.Net:=Number;
  1161.                     TmpAdr.Node:=0;
  1162.                     TmpAdr.Point:=0;
  1163.                   END ELSE
  1164.                   IF (KeyWord='POINT') THEN
  1165.                   BEGIN
  1166.                     TmpAdr.Point:=Number;
  1167.                   END ELSE
  1168.                   BEGIN
  1169.                     TmpAdr.Node:=Number;
  1170.  
  1171.                     Done:=False;
  1172.                     Ifn:=0;
  1173.                     i:=-1;
  1174.                     WHILE NOT Done AND (i<NodelistIndexNum-1) AND (ifn<=CurrentTextFileNumber) DO
  1175.                     BEGIN
  1176.                       Inc(i);
  1177.                       NodeListIndex.RetA(i,0,QIdx);
  1178.                       CASE Cfg.NodeListTyp OF
  1179.                         RANodeListType,
  1180.                         SBBSNodeListType,
  1181.                         QBBSNodeListType : BEGIN
  1182.                           WITH QIdx DO
  1183.                           BEGIN
  1184.                             OurZone:=TmpAdr.Zone;
  1185.                             OurNet:=TmpAdr.Net;
  1186.                             ifn:=RawFile;
  1187.                             io:=RawPos;
  1188.                             IF ifn>CurrentTextFileNumber THEN Break;
  1189.                             IF (NodeType=ntZone) THEN TmpAdr.Zone:=Number ELSE
  1190.                               IF (NodeType=ntRegion) OR (NodeType=ntNet) THEN TmpAdr.Net:=Number;
  1191.                           END;
  1192.                         END;
  1193.                       END;
  1194.                       IF ((ifn=CurrentTextFileNumber) AND (io>tfpos)) OR (i=NodeListIndexNum-2) THEN
  1195.                       BEGIN
  1196.                         Done:=True;
  1197.                         TmpAdr.Zone:=OurZone;
  1198.                         TmpAdr.Net:=OurNet;
  1199.                       END;
  1200.                     END;
  1201.                   END;
  1202.                   NodePos:=TfPos;
  1203.                   ConvRaNodeListRec(s,NListRec,TmpAdr.Zone,TmpAdr.Net,TmpAdr.Node);
  1204.                   FindPreviousNode:=True;
  1205.                 END ELSE
  1206.                   FindPreviousNode:=False;
  1207.               END;
  1208.             END;
  1209.           END;
  1210.         END;
  1211.       END;
  1212.     END;
  1213.   END;
  1214.  
  1215. END.
  1216.